package com.zcs.app.lucky.ui

import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.content.Intent
import android.content.res.ColorStateList
import android.view.View
import android.widget.SeekBar
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.lifecycleScope
import cn.sxw.android.base.dialog.CustomDialogHelper
import cn.sxw.android.base.kt.BaseViewModel
import cn.sxw.android.base.utils.GlideStaticUtils
import cn.sxw.android.base.utils.JDateKit
import cn.sxw.android.base.utils.JLogUtil
import com.alibaba.fastjson.JSON
import com.safframework.delegate.extras.extraDelegate
import com.zcs.app.lucky.R
import com.zcs.app.lucky.base.BaseLuckyActivity
import com.zcs.app.lucky.data.LuckyDataCache
import com.zcs.app.lucky.databinding.ActivityLuckingBinding
import com.zcs.app.lucky.databinding.ItemLuckyAvatarBinding
import com.zcs.app.lucky.entity.LuckyEntity
import com.zcs.app.lucky.entity.LuckyPeople
import com.zcs.app.lucky.entity.LuckyResultEntity
import com.zcs.app.lucky.entity.PrizeEntity
import com.zcs.app.lucky.helper.AnimatorHelper
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.util.*
import kotlin.collections.ArrayList
import kotlin.random.Random

class LuckingActivity : BaseLuckyActivity<ActivityLuckingBinding, BaseViewModel>() {
    companion object {
        const val TAG = "Lucking/D"
        const val MODE_UNSPECIFIED = -1
        const val MODE_MANUAL = 0
        const val MODE_AUTO = 1
    }

    private var currMode = MODE_UNSPECIFIED

    override fun needViewModel(): Boolean = false
    private val mId by extraDelegate(KEY_ID, "")
    private val mLucky: LuckyEntity? by lazy {
        LuckyDataCache.findByIdOnNull(mId)
    }
    private var mPrize: PrizeEntity? = null
    private var mPickCount = 0// 本次抽奖人数
    private val userList = ArrayList<ItemLuckyAvatarBinding>()
    private val luckyUserList = ArrayList<ItemLuckyAvatarBinding>()
    private val unLuckyCount = MutableLiveData<Int>()

    // 懒加载机制
    override fun isLazyInit() = true
    override fun onReady() {
        binding.toolbar.tvToolbarTitle.text = "正在抽奖..."
        binding.loadingLayout.visibility = View.VISIBLE
    }

    override fun onInit() {
        initView()
        if (mId.isEmpty() || mLucky == null) {
            showExitMessageDialog("数据异常")
            return
        }
        initObserve()
        initData()
    }

    override fun initObserve() {
        unLuckyCount.observe(this, {
            binding.tvUnluckyCount.text = "剩余未中奖人数：$it 人"
        })

        binding.seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                mPickCount = progress
                if (progress == 0) {
                    seekBar?.progress = 1
                    mPickCount = 1
                }
                binding.tvLabel2.text = "本次抽奖名额：$mPickCount 人"
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {}

            override fun onStopTrackingTouch(seekBar: SeekBar?) {}
        })
    }

    private val canvasWidth by lazy { binding.avatarCanvas.width }
    private val canvasHeight by lazy { binding.avatarCanvas.height }
    private val radius by lazy { binding.space.width / 2f }
    private val maxX by lazy { canvasWidth - radius * 2f }
    private val maxY by lazy { canvasHeight - radius * 2f }

    override fun initData() {
        // hide loading last
        hideLoading()
        adapterHelper.prizeList.clear()
        adapterHelper.prizeList.addAll(mLucky!!.prizeList)
        adapterHelper.initPrizeAdapter(binding.rvPrize, checkable = true, horizontal = true) {
            binding.seekBar.progress = 0
            if (it.maxCount <= 0) {
                showMessage("当前奖品已抽完，请选择其他奖品")
                return@initPrizeAdapter
            }
            mPrize = it
            binding.seekBar.visibility = View.VISIBLE
            binding.seekBar.max = it.maxCount
            binding.seekBar.progress = 1
        }

        unLuckyCount.value = mLucky!!.group!!.list.size
    }

    // 清除缓存并继续抽奖
    private fun clearAndResumeLucky() {
        luckyUserList.clear()
        isFirst = false
        showResultCount = 0
        clearMode()
        for (p in adapterHelper.prizeList)
            p.isChecked = false
        adapterHelper.prizeAdapter?.notifyDataSetChanged()
        binding.resultLayout.visibility = View.INVISIBLE
        binding.ivYanhua.visibility = View.INVISIBLE
        binding.avatarCanvas.visibility = View.INVISIBLE
        binding.settingLayout.visibility = View.VISIBLE
        binding.seekBar.visibility = View.INVISIBLE
        binding.btnPreview.visibility = View.VISIBLE
        binding.btnFinish.visibility = View.VISIBLE
        mPrize = null
        mPickCount = 0
        binding.tvLabel2.text = "请选择本次抽奖奖品！"
    }

    private fun clearMode() {
//        currMode = MODE_UNSPECIFIED
//        binding.ckManual.isSelected = false
//        binding.ckAuto.isSelected = false
    }

    private var isFirst = true
    private var isRunning = false
    private fun ready2go() {
        // check
        if (mPickCount > unLuckyCount.value!!) {
            showMessage("中奖名额不得大于未中奖人数，请重新设置。")
            return
        }
        if (currMode == MODE_UNSPECIFIED) {
            showMessage("请设置抽奖模式")
            return
        }

        binding.settingLayout.visibility = View.GONE
        binding.btnPick.visibility = if (currMode == MODE_AUTO) View.GONE else View.VISIBLE
        binding.avatarCanvas.visibility = View.VISIBLE

        if (isFirst) {
            for (user in mLucky!!.group!!.list) {
                val avatar = ItemLuckyAvatarBinding.inflate(layoutInflater)
                // 缓存
                userList.add(avatar)
                // 加载头像
                GlideStaticUtils.displayCircleImage(
                    user.avatar, R.mipmap.ic_launcher_round, avatar.ivAvatar
                )
                avatar.tvName.text = user.name
                avatar.root.tag = JSON.toJSONString(user)
                // 添加到Canvas
                binding.avatarCanvas.addView(avatar.root)
                // 随机位置
                avatar.root.translationX = Random.nextInt(maxX.toInt()).toFloat()
                avatar.root.translationY = Random.nextInt(maxY.toInt()).toFloat()
            }
        }

        isRunning = true
        startRunning()
    }

    private fun startRunning() {
        lifecycleScope.launch(Dispatchers.Main) {
            for (view in userList) {
                isRunning = true
                startTranslation(
                    view.root,
                    AnimatorHelper.randomSpeed(),
                    AnimatorHelper.randomSpeed()
                )
            }
            // 开启自动抽奖监听
            if (currMode == MODE_AUTO)
                pickOnAuto()
        }
    }

    private fun pickOnAuto() {
        lifecycleScope.launch {
            delay(6_000)
            pickLuckyMan()
            if (isRunning)
                pickOnAuto()
        }
    }

    private fun startTranslation(v: View, speedX: Float, speedY: Float) {
        if (!isRunning || v.isSelected) return
        var sx = speedX
        var x1 = v.translationX + speedX
        if (x1 > maxX) {
            x1 = maxX
            sx = AnimatorHelper.calcSpeed(sx)
        } else if (x1 < 0) {
            x1 = 0f
            sx = AnimatorHelper.calcSpeed(sx)
        }
        v.translationX = x1

        var y1 = v.translationY + speedY
        var sy = speedY
        if (y1 > maxY) {
            y1 = maxY
            sy = AnimatorHelper.calcSpeed(sy)
        } else if (y1 < 0) {
            y1 = 0f
            sy = AnimatorHelper.calcSpeed(sy)
        }
        v.translationY = y1
        lifecycleScope.launch(Dispatchers.Main) {
            delay(AnimatorHelper.ANIM_DELAY)
            startTranslation(v, sx, sy)
        }
    }

    /**
     * 抽奖核心逻辑
     */
    private fun pickLuckyMan() {
        /**
         * 随机数的产生，是根据一定的算法---线性同余公式（linear congruential formula）产生的。
         * Java中随机数的产生是根据是一定的算法产生的，因此有一定的规律。
         * 只要两个Random实例的种子一样，那么他们的第n次nextXXX就一定是一样的。
         *
         * 所以这里我们使用随机种子来确保结果不能被预测
         */
        val seed = UUID.randomUUID().hashCode()
        // 1.产生随机数字
        val luckyNo = Random(seed).nextInt(userList.size)

        // 2.找到幸运者
        val luckyMan = userList[luckyNo]
        luckyMan.root.isSelected = true
        // 3.缓存幸运者
        luckyUserList.add(luckyMan)
        // 4.将幸运者从大名单移除
        userList.removeAt(luckyNo)
        // 5.刷新剩余未中奖人数
        unLuckyCount.postValue(userList.size)
        // 6.如果中奖者名额已够 或者 未中奖人数为0，结束本次抽奖
        if (luckyUserList.size >= mPickCount || userList.isEmpty()) {
            isRunning = false
            binding.btnPick.visibility = View.GONE
        }
        // 7.放大显示幸运者
        showLuckyMan(luckyMan)
    }

    private var showResultCount = 0
    private fun showLuckyResult() {
        if (showResultCount > 0)
            return
        showResultCount++
        JLogUtil.d("showLuckyResult called in ${JDateKit.currDateTime()}")
        mPrize?.let {
            it.maxCount -= mPickCount
        }
        binding.btnPick.visibility = View.GONE
        binding.avatarCanvas.visibility = View.INVISIBLE
        binding.resultLayout.visibility = View.VISIBLE
        binding.ivYanhua.visibility = View.VISIBLE

        adapterHelper.userList.clear()
        for (a in luckyUserList) {
            JLogUtil.d(TAG, "tag = ${a.root.tag}")
            val user = JSON.parseObject(a.root.tag.toString(), LuckyPeople::class.java)
            adapterHelper.userList.add(user)
        }

        // 缓存数据
        val resultChild = LuckyResultEntity()
        resultChild.prize = mPrize?.copy()
        resultChild.userList.addAll(adapterHelper.userList)
        mLucky!!.resultList.add(resultChild)
        LuckyDataCache.update(mLucky!!)

        when (adapterHelper.userList.size) {
            1, 2 -> {
                adapterHelper.userList.add(0, LuckyPeople())
                adapterHelper.userList.add(LuckyPeople())
            }
        }
        val spanCount = if (adapterHelper.userList.size == 3) 3 else 4
        adapterHelper.initUserAdapter(binding.rvUsers, spanCount) {}
        // 设置奖品信息
        binding.tvName.text = mPrize?.name
        binding.tvLevel.text = mPrize?.level?.name
        GlideStaticUtils.displayImage(
            mPrize?.pic,
            R.drawable.empty_photo,
            binding.ivThumb
        )
    }

    private fun showLuckyMan(bind: ItemLuckyAvatarBinding) {
        val luckyMan = bind.root
        luckyMan.isSelected = true
        // 移除
        binding.avatarCanvas.removeViewInLayout(luckyMan)
        // 重新添加，使其出现在最上面
        binding.avatarCanvas.addView(luckyMan)
        bind.tvName.visibility = View.VISIBLE
        val tx = ObjectAnimator.ofFloat(
            luckyMan, "translationX",
            luckyMan.translationX, (canvasWidth - luckyMan.width) * 0.5f
        )
        val ty = ObjectAnimator.ofFloat(
            luckyMan, "translationY",
            luckyMan.translationY, (canvasHeight - luckyMan.height) * 0.5f
        )
        val sx = ObjectAnimator.ofFloat(luckyMan, "scaleX", 1f, 3f, 2f)
        val sy = ObjectAnimator.ofFloat(luckyMan, "scaleY", 1f, 3f, 2f)
        // 方向回正
        val ra = ObjectAnimator.ofFloat(luckyMan, "rotation", luckyMan.rotation, 0f)

        val set = AnimatorSet()
        set.duration = 666
        set.playTogether(tx, ty, sx, sy, ra)
        set.start()
        // 展示后移除
        lifecycleScope.launch(Dispatchers.Main) {
            delay(666 * 2)
            binding.avatarCanvas.removeViewInLayout(luckyMan)
            delay(300)
            if (!isRunning && showResultCount == 0) {// 抽奖结束了
                showLuckyResult()
            }
        }
    }

    override fun initView() {
    }

    override fun hideLoading() {
        super.hideLoading()
        binding.loadingLayout.visibility = View.GONE
    }

    override fun addOnClickListener() {
        binding.btnPreview.setOnClickListener {
            val intent = Intent(this, LuckyResultActivity::class.java)
            intent.putExtra(KEY_ID, mId)
            intent.putExtra(KEY_BOOLEAN, false)
            launchActivity(intent)
        }
        binding.btnFinish.setOnClickListener {
            CustomDialogHelper.showCustomConfirmDialog(this,
                "你确定要结束本次抽奖吗？", object : CustomDialogHelper.NativeDialogCallback {
                    override fun onConfirm() {
                        showToast("抽奖已结束")
                        killMyself()
                        binding.btnPreview.performClick()
                    }

                    override fun onCancel() {
                    }
                })
        }
        binding.btnContinue.setOnClickListener {
            // 继续抽奖
            clearAndResumeLucky()
        }
        binding.btnPick.setOnClickListener {
            lifecycleScope.launch(Dispatchers.Main) {
                it.isEnabled = false
                pickLuckyMan()
                delay(666 * 2)
                it.isEnabled = true
            }
        }

        binding.toolbar.ivToolbarBack.setOnClickListener { onBackPressed() }
        binding.btnStart.setOnClickListener {
            if (mPrize == null || binding.seekBar.progress < 1) {
                showMessage("请选择奖品")
                return@setOnClickListener
            }
            ready2go()
        }
        // 模式设置
        binding.ckManual.setOnClickListener { switchCheckBox(MODE_MANUAL) }
        binding.tvManual.setOnClickListener { switchCheckBox(MODE_MANUAL) }
        binding.ckAuto.setOnClickListener { switchCheckBox(MODE_AUTO) }
        binding.tvAuto.setOnClickListener { switchCheckBox(MODE_AUTO) }
    }

    private fun switchCheckBox(mode: Int) {
        if (currMode == mode) return
        currMode = mode

        binding.ckAuto.isSelected = currMode == MODE_AUTO
        binding.ckManual.isSelected = currMode == MODE_MANUAL
        val tint = ColorStateList.valueOf(0xFF13C1C1.toInt())
        binding.ckAuto.imageTintList = if (currMode == MODE_AUTO) null else tint
        binding.ckManual.imageTintList = if (currMode == MODE_MANUAL) null else tint
    }

    override fun onBackPressed() {
        CustomDialogHelper.showCustomConfirmDialog(
            this,
            "你确定要结束本次抽奖吗？",
            object : CustomDialogHelper.NativeDialogCallback {
                override fun onConfirm() {
                    if (mLucky!!.canLucky()) {
                        showExitMessageDialog("抽奖已结束")
                    } else {
                        showToast("抽奖已结束")
                        killMyself()
                        binding.btnPreview.performClick()
                    }
                }

                override fun onCancel() {}
            })
    }
}